package com.fc.happyteam.helper;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.lang.String.format;

/**
 * Some common basic string functions.
 * 
 */
public final class StringUtils {

    private static Pattern phonePattern = Pattern.compile("^1[3|4|5|7|8]\\d{9}$");

    private StringUtils() {
    }

    /**
     * used to do token replacement on a string using the properties specified, with the specified prefix, and specified suffix.
     * 
     * @param input
     * @param properties
     * @param prefix
     * @param suffix
     * @return the replaced string
     */
    public static String tokenReplace(String input, Map<String, String> properties, String prefix, String suffix) {
        if (properties != null && hasValue(prefix) && hasValue(suffix)) {
            for (String key : properties.keySet()) {
                String value = properties.get(key);
                input = input.replace(String.format("%s%s%s", prefix, key, suffix), value);
            }

            return input;
        } else {
            return input;
        }
    }

    /**
     * makes a string from the specified array.
     * 
     * @param objects
     * @param prefix
     * @param suffix
     * @param seperator
     * @return string from the specified arra
     */
    public static String mkString(Object[] objects, String prefix, String suffix, String seperator) {
        StringBuilder builder = new StringBuilder();
        boolean first = true;
        builder.append(prefix);

        for (Object o : objects) {
            if (!first) {
                builder.append(seperator);
            }
            builder.append(o.toString());
            first = false;
        }

        builder.append(suffix);
        return builder.toString();
    }

    /**
     * @see StringUtils#mkString(Object[], String, String, String)
     */
    public static String mkString(List<?> objects, String prefix, String suffix, String seperator) {
        return mkString(objects.toArray(), prefix, suffix, seperator);
    }

    /**
     * returns true if the specified string is empty or has 0 length.
     * 
     * @param value
     * @return true if the specified string is empty or has 0 length
     */
    public static boolean isEmpty(String value) {
        return (null == value || value.length() == 0);
    }

    /**
     * @param value
     * @return null if the specified value is empty
     */
    public static String nullIfEmpty(String value) {
        if (StringUtils.isEmpty(value)) {
            return null;
        }

        return value;
    }

    /**
     * inverse of {@link StringUtils#isEmpty(String)}.
     */
    public static boolean hasValue(String value) {
        return !isEmpty(value);
    }

    /**
     * ensures the specified value starts with the startWith value.
     * 
     * @param value
     *            the value to ensure that it starts with
     * @param startWith
     *            the value to ensure it starts with
     * @return the string, ensuring it starts with the specified value.
     */
    public static String startingWith(String value, String startWith) {
        if (value.startsWith(startWith)) {
            return value;
        }

        return startWith + value;
    }

    /**
     * if the specified string starts with the 'startWith' variable then the value is returned without it.
     * 
     * @param value
     * @param startWith
     * @return the specified value without the startWith value
     */
    public static String notStartingWith(String value, String startWith) {
        if (value.startsWith(startWith)) {
            return value.substring(startWith.length(), value.length());
        }

        return value;
    }

    /**
     * opposite of @see {@link StringUtils}.{@link #notStartingWith(String, String)}
     */
    public static String notEndingWith(String value, String ending) {
        if (value.endsWith(ending)) {
            return value.substring(0, value.length() - ending.length());
        }

        return value;
    }

    /**
     * opposite of @see {@link StringUtils}.{@link #startingWith(String, String)}
     */
    public static String endingWith(String value, String ending) {
        if (value.endsWith(ending)) {
            return value;
        }

        return value + ending;
    }

    /**
     * takes the specified string, and a seperator returns from the last index of that character to the end.
     * 
     * @param seperator
     * @return the substring of the given string starting from the last occurence of the separator
     */
    public static String suffix(String str, String seperator) {
        int index = str.lastIndexOf(seperator);

        if (index > 0) {
            int offset = index + seperator.length();
            return str.substring(offset, str.length());
        }

        throw new IllegalArgumentException(format("string does not contain the character %s, unable to derive suffix", seperator));
    }

    /**
     * encodes the specified value as a utf-8 url encoded value.
     * 
     * @param value
     * @return utf-8 url-encoded string
     */
    public static String urlEncode(String value) {
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * Determines if the input String contains any of the input characters.
     * 
     * @param s
     *            the String.
     * @param chars
     *            the characters to check.
     * @return true if any of the input characters are found in the input String.
     */
    public static boolean containsAny(String s, String chars) {
        for (int i = 0; i < chars.length(); i++) {
            if (s.contains(Character.toString(chars.charAt(i)))) {
                return true;
            }
        }

        return false;
    }

    /**
     * Convert the provided InputStream to a String.
     * 
     * @param is
     *            The InputStream.
     * @return the InputStream as a String.
     * @throws IOException
     *             If an error occurred.
     */
    public static String convertStreamToString(InputStream is) throws IOException {
        if (is != null) {
            StringBuilder sb = new StringBuilder();
            String line;

            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append("\n");
                }
            } finally {
                is.close();
            }
            return sb.toString();
        } else {
            return "";
        }
    }

    public static boolean isPhoneString(String src) {
        boolean return_value = false;
        if (src != null && src.length() > 0) {
            Matcher m = phonePattern.matcher(src);
            if (m.find()) {
                return_value = true;
            }
        }
        return return_value;
    }

    public static String createLinkString(Map<String, Object> params) {

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        StringBuffer prestr = new StringBuffer();

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = (String)params.get(key);

            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("&");
            }
        }

        return prestr.toString();
    }

    /**
     * <p>Checks if a String is whitespace, empty ("") or null.</p>
     *
     * <pre>
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * </pre>
     *
     * @param str  the String to check, may be null
     * @return <code>true</code> if the String is null, empty or whitespace
     * @since 2.0
     */
    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
}
